#! /usr/bin/perl -w

# Author  : huanlf@gmail.com
# Credit  : linux_lyb@gmail.com - thinks for the bug fixing
# License : GPL v2

# This script is used to search files in a specified ftp server

use strict;
use Net::FTP;
use Getopt::Long;

## uncomment to get verbose output
#use Smart::Comments;

Getopt::Long::Configure( 'no_ignore_case' );
$|++;

my @found; # to store what we get, not useful at the current
my %opt;   # to get command options/flags

GetOptions (
    "maxdep|m=i"  => \$opt{'maxdep'},
    "regexp|r=s"  => \$opt{regexp},
    "basedir|b=s" => \$opt{basedir},
    "ignore-case" => \$opt{'ignore-case'},
    "host|s=s"    => \$opt{host},
    "port|P=i"    => \$opt{port},
    "user|u=s"    => \$opt{user},
    "passwd|p=s"  => \$opt{passwd},
    "debug|d=i"   => \$opt{debug},
    "verbose|v"   => \$opt{verbose},
    "help|h"      => sub { help() },
);

## set default optionls' values
$opt{maxdep}     ||= 65535;
$opt{regexp}     ||= qr{\.(rm|rmvb|avi|dat|mp3|wma)$};
$opt{basedir}    ||= qq{/};
$opt{host}       ||= qq{localhost};
$opt{port}       ||= 21;
$opt{user}       ||= qq{ftp};
$opt{passwd}     ||= qq{anonymous};

### optitions: %opt

## connect to ftp server 
my $ftp = Net::FTP->new( $opt{host},
                         Port  => $opt{port},
                         Debug => $opt{debug}
  ) or die "Can not connect to ftp server: $@";
$ftp->login( $opt{user}, $opt{passwd} )
    or die "Can not login: ", $ftp->message; 

my $level = 0;
&find_files( $opt{basedir} );

## ------------------- the core sub ------------------
sub find_files($) {
    my $dir = shift;

    if ( $level +1 > $opt{maxdep} ) {
        ### to deep, back
        return 0;
    }

    # we may have no permition to enter this dir
    unless ( $ftp->cwd( $dir ) ) {
        ### cdfailed: $ftp->message
        ### faildir: $dir
        ### pwd: $ftp->pwd
        ### ---
        return 0;
    }

    my $pwd = $ftp->pwd();
    $level++;
    ### cd into: $pwd
    ### dep: $level
    ### ---

    my @tmp = $ftp->dir;
    ## get the node name, and its' property. ignore link. 
    my %files = map { (split)[-1, 0] } grep /^[^l]+/, @tmp;
    # ### %files 

    ### keys: keys %files
    for my $f ( sort { $files{$a} cmp $files{$b} } keys %files ) {
        if ( $files{ $f } =~ /^d/o) {
            # ### dir: $files{ $f }, $f
            &find_files( $f ); 
        }
        else {
            # ### non-dir: $files{ $f }, $f
            if ( &check_regexp( $f ) ) {
                my $file =  $pwd . "/$f";
                push @found, $file;
                # ### Found: $pwd . "/". $f
                print "ftp://$opt{user}:$opt{passwd}" .
                      "\@$opt{host}:$opt{port}"
                      if $opt{verbose};
                print "$file\n";
            }
        }
    } 

    $level--;
    $ftp->cdup;
    ### cdup to: $ftp->pwd
    ### ---
    1;
}
# -------------------------------------

## check the file if match regexp
sub check_regexp($) {
    my $file = shift;

    $opt{'ignore-case'} ?
    $file =~ m{$opt{regexp}}io:
    $file =~ m{$opt{regexp}}o;
}

# -------------------------------------
## print help message and exit
sub help {
    ( my $msg = <<"    EOF" ) =~ s/^\s+/  /mg;
    Usage: $0 [ options ]
    --maxdep      | -m : how much further to to
    --regexp      | -r : perl regexp to match the file to retrive
    --basedir     | -b : which dir to start
    --ignore-case | -i : case insensitive matching
    --host        | -s : ftp server
    --port        | -P : server service port
    --user        | -u : the user to login
    --passwd      | -p : the password of the user
    --debug       | -d : show ftp debug message
    --verbose     | -v : show result in verbose
    --help        | -h : display this help message
    EOF
    warn $msg;
    exit 0;
}

__END__
